package hservice

import (
	"fmt"
	// "sync"
	"strings"
	"time"

	"advertoper/db"
	"advertoper/errorcode"
	"advertoper/rpc/client/push"
	"advertoper/rpc/client/zjservice"

	"doubimeizhi.com/datatable"
	"doubimeizhi.com/utility"

	log "github.com/cihub/seelog"
)

var (
	defaultZJSeckillUserService *ZJSeckillUserService
)

type ZJSeckillUserService struct {
}

func newZJSeckillUserService() *ZJSeckillUserService {
	service := &ZJSeckillUserService{}
	go service.queryPushTask()
	go service.queryseckillCallTask()
	return service
}

func GetZJSeckillUserService() *ZJSeckillUserService {
	if defaultZJSeckillUserService == nil {
		defaultZJSeckillUserService = newZJSeckillUserService()
	}
	return defaultZJSeckillUserService
}

//提醒我struct
type PushCallUserReq struct {
	Title     string `json:"title"`
	Texts     string `json:"text"`
	Router    string `json:"router"`
	SeckillId int    `json:"seckill_id"`
}

//秒杀提醒我功能
func (p *ZJSeckillUserService) PushCallUser(userid string, plat int, req *PushCallUserReq) (uint, string) {
	nowTick := time.Now().Unix()
	//得到任务时间，秒杀开始前5分钟
	item := GetZJSeckillInfoService().GetZJSeckillItemById(req.SeckillId)
	if item == nil {
		return 70001, "该秒杀商品不存在"
	}
	if item.Status != 1 {
		return 70001, "该秒杀商品不存在"
	}
	taskTick := item.SeckillStart - 5*60
	if nowTick >= taskTick {
		return 70002, "距秒杀开始小于等于5分钟~"
	}
	//查询是否已经订阅
	sql := `select count(0) num from seckill_push_task where userid=? and status=1 and seckill_id=?`
	mysqlHelper2 := db.GetHomePageInfoMysqlHelper()
	results2, err2 := mysqlHelper2.Query(sql, userid, req.SeckillId)
	if err2 != nil {
		log.Errorf("查询用户是否已经订阅失败 ,~~~PushCallUser,err is %s", err2.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR)
	}
	num := mysqlHelper2.GetColInt(results2[0], "num")
	if num > 0 {
		return 70003, "该秒杀已经订约过~"
	}

	if plat == 1 {
		req.Texts = fmt.Sprintf("您订阅的%s秒杀将在五分钟后开始！不要错过哦~", req.Title)
		req.Title = "指尖到家"
	} else {
		req.Texts = fmt.Sprintf("您订阅的%s秒杀将在五分钟后开始！不要错过哦~", req.Title)
		req.Title = ""
	}

	//保存任务表
	data := make(map[string]*utility.MySQLFieldValue)
	data["userid"] = utility.NewMySQLFieldValue(userid, false)
	data["task_tick"] = utility.NewMySQLFieldValue(taskTick, false)
	data["seckill_id"] = utility.NewMySQLFieldValue(req.SeckillId, false)
	data["title"] = utility.NewMySQLFieldValue(req.Title, false)
	data["texts"] = utility.NewMySQLFieldValue(req.Texts, false)
	data["router"] = utility.NewMySQLFieldValue(req.Router, false)
	data["status"] = utility.NewMySQLFieldValue(1, false)
	data["insert_tick"] = utility.NewMySQLFieldValue(nowTick, false)
	data["update_tick"] = utility.NewMySQLFieldValue(nowTick, false)
	mysqlHelper := db.GetHomePageInfoMysqlHelper()
	_, err := mysqlHelper.SaveRecord(data, "seckill_push_task")
	if err != nil {
		log.Errorf("保存秒杀推送任务失败 ,~~~PushCallUser,err is %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR)
	}
	return errorcode.EC_GL_SUCCESS, errorcode.Msg(errorcode.EC_GL_SUCCESS)
}

//查用户设置了秒杀提醒的秒杀id
func (p *ZJSeckillUserService) CallSeckillQuery(userid string) (uint, string, []int) {
	seckillIds := make([]int, 0)
	sql := `select seckill_id from seckill_push_task where userid=? and status=1`
	mysqlHelper := db.GetHomePageInfoMysqlHelper()
	results, err := mysqlHelper.Query(sql, userid)
	if err != nil {
		log.Errorf("查询设置提醒的秒杀id失败 ,~~~CallSeckillQuery,err is %s", err.Error())
		return errorcode.EC_GL_INTERNAL_ERROR, errorcode.Msg(errorcode.EC_GL_INTERNAL_ERROR), seckillIds
	}
	for _, dt := range results {
		seId := mysqlHelper.GetColInt(dt, "seckill_id")
		seckillIds = append(seckillIds, seId)
	}
	return errorcode.EC_GL_SUCCESS, errorcode.Msg(errorcode.EC_GL_SUCCESS), seckillIds
}

//扫描推送“提醒我”任务
func (p *ZJSeckillUserService) queryPushTask() {
	defer func() {
		if err := recover(); err != nil {
			log.Errorf("扫描推送“提醒我”任务异常,err: %v", err)
		}
		//重启定时任务
		go p.queryPushTask()
	}()

	for {
		select {
		case <-time.After(time.Second * 10):
			//先查到所有有效任务
			nowtime := time.Now().Unix()
			daq := datatable.NewDataTableQuery()
			daq.SetTableName("seckill_push_task")
			daq.PushField(&datatable.FiledItem{Alias: "userid", Field: "userid"})
			daq.PushField(&datatable.FiledItem{Alias: "title", Field: "title"})
			daq.PushField(&datatable.FiledItem{Alias: "texts", Field: "texts"})
			daq.PushField(&datatable.FiledItem{Alias: "router", Field: "router"})
			daq.PushField(&datatable.FiledItem{Alias: "seckill_id", Field: "seckill_id"})
			daq.PushCondition("task_tick <= ?", nowtime)
			daq.PushCondition("status = ?", 1)
			sql, values := daq.GenerateSQL()
			mysqlHelper := db.GetHomePageInfoMysqlHelper()
			results, err := mysqlHelper.Query(sql, values...)
			if err != nil {
				//log.Errorf("query push task  fail ,~~~queryPushTask,err is %s", err.Error())
				return
			}
			for _, dt := range results {
				userid := mysqlHelper.GetColString(dt, "userid")
				userids := []string{userid}
				title := mysqlHelper.GetColString(dt, "title")
				texts := mysqlHelper.GetColString(dt, "texts")
				router := mysqlHelper.GetColString(dt, "router")
				resp := push.PushMsg("notification", title, texts, router, "", userids)
				if resp == nil {
					log.Errorf("push 请求发送失败~")
				} else {
					if resp.Code != 0 {
						log.Errorf("psu失败~,code :%d, msg : %s", resp.Code, resp.Msg)
					} else if resp.Msg == "success" {
						log.Infof("push成功：uid： %s", userid)
					}
				}
				//任务置为无效
				seckillId := mysqlHelper.GetColInt(dt, "seckill_id")
				p.UpdatePushTask(userid, seckillId)

			}
		}
	}
}

//将任务置为无效
func (p *ZJSeckillUserService) UpdatePushTask(userid string, seckillId int) {
	updaq := datatable.NewDataTableUpdate()
	updaq.SetTableName("seckill_push_task")
	updaq.SetUpdateValue("status=?", -1)
	updaq.SetUpdateValue("update_tick=?", time.Now().Unix())
	updaq.PushCondition("userid=?", userid)
	updaq.PushCondition("seckill_id=?", seckillId)
	sql, values := updaq.GenerateSQL()
	mysqlHelper := db.GetHomePageInfoMysqlHelper()
	_, err := mysqlHelper.Exec(sql, values...)
	if err != nil {
		log.Errorf("修改推送定时任务失效失败 ,~~~UpdatePushTask,err is %s", err.Error())
	}
}

//存秒杀通知任务
func (p *ZJSeckillUserService) AddSeckillCallTask(seckillId, pId int, pSId int64, callStatus, price int, taskTick int64, regionCode string) bool {
	nowTick := time.Now().Unix()
	data := make(map[string]*utility.MySQLFieldValue)
	data["seckill_id"] = utility.NewMySQLFieldValue(seckillId, false)
	data["seckill_product_id"] = utility.NewMySQLFieldValue(pId, false)
	data["seckill_product_sid"] = utility.NewMySQLFieldValue(pSId, false)
	data["seckill_price"] = utility.NewMySQLFieldValue(price, false)
	data["task_tick"] = utility.NewMySQLFieldValue(taskTick, false)
	data["call_status"] = utility.NewMySQLFieldValue(callStatus, false)
	data["region_code"] = utility.NewMySQLFieldValue(regionCode, false)
	data["status"] = utility.NewMySQLFieldValue(1, false)
	data["insert_tick"] = utility.NewMySQLFieldValue(nowTick, false)
	data["update_tick"] = utility.NewMySQLFieldValue(nowTick, false)
	mysqlHelper := db.GetHomePageInfoMysqlHelper()
	_, err := mysqlHelper.SaveRecord(data, "seckill_call_task")
	if err != nil {
		log.Errorf("存秒杀通知任务失败，err: %s", err.Error())
		return false
	}
	return true
}

// 秒杀通知任务置为无效
func (p *ZJSeckillUserService) CanclSeckillCallTask(seckillId, callStatus int) {
	updaq := datatable.NewDataTableUpdate()
	updaq.SetTableName("seckill_call_task")
	updaq.SetUpdateValue("status=?", -1)
	updaq.SetUpdateValue("update_tick=?", time.Now().Unix())
	updaq.PushCondition("call_status=?", callStatus)
	updaq.PushCondition("seckill_id=?", seckillId)
	sql, values := updaq.GenerateSQL()
	mysqlHelper := db.GetHomePageInfoMysqlHelper()
	_, err := mysqlHelper.Exec(sql, values...)
	if err != nil {
		log.Errorf("将秒杀任务置为无效，err: %s", err.Error())
	}
	log.Infof("秒杀通知任务置为无效成功~id %d, callStatus:%d", seckillId, callStatus)
}

// 重置秒杀通知任务
func (p *ZJSeckillUserService) UpdateSeckillCallTask(seckillId, callStatus int, taskTick int64) {
	updaq := datatable.NewDataTableUpdate()
	updaq.SetTableName("seckill_call_task")
	updaq.SetUpdateValue("task_tick=?", taskTick)
	updaq.SetUpdateValue("update_tick=?", time.Now().Unix())
	updaq.PushCondition("call_status=?", callStatus)
	updaq.PushCondition("seckill_id=?", seckillId)
	updaq.PushCondition("status=?", 1)
	sql, values := updaq.GenerateSQL()
	mysqlHelper := db.GetHomePageInfoMysqlHelper()
	_, err := mysqlHelper.Exec(sql, values...)
	if err != nil {
		log.Errorf("将秒杀任务通知时间修改失败，err: %s", err.Error())
	}
}

//扫描秒杀通知任务,并通知服务中心
func (p *ZJSeckillUserService) queryseckillCallTask() {
	defer func() {
		if err := recover(); err != nil {
			log.Errorf("扫描秒杀通知任务异常,err: %v", err)
		}
		//重启定时任务
		go p.queryseckillCallTask()
	}()

	for {
		select {
		case <-time.After(time.Second * 10):
			//先查到所有有效任务
			nowtime := time.Now().Unix()
			daq := datatable.NewDataTableQuery()
			daq.SetTableName("seckill_call_task")
			daq.PushField(&datatable.FiledItem{Alias: "seckill_id", Field: "seckill_id"})
			daq.PushField(&datatable.FiledItem{Alias: "seckill_product_id", Field: "seckill_product_id"})
			daq.PushField(&datatable.FiledItem{Alias: "seckill_product_sid", Field: "seckill_product_sid"})
			daq.PushField(&datatable.FiledItem{Alias: "seckill_price", Field: "seckill_price"})
			daq.PushField(&datatable.FiledItem{Alias: "call_status", Field: "call_status"})
			daq.PushField(&datatable.FiledItem{Alias: "region_code", Field: "region_code"})
			daq.PushCondition("task_tick <= ?", nowtime)
			daq.PushCondition("status = ?", 1)
			sql, values := daq.GenerateSQL()
			mysqlHelper := db.GetHomePageInfoMysqlHelper()
			results, err := mysqlHelper.Query(sql, values...)
			if err != nil {
				//log.Errorf("query call task  fail ,~~~queryseckillCallTask,err is %s", err.Error())
				return
			}
			for _, dt := range results {
				productId := mysqlHelper.GetColInt(dt, "seckill_product_id")
				productSId := mysqlHelper.GetColInt64(dt, "seckill_product_sid")
				price := mysqlHelper.GetColInt(dt, "seckill_price")
				callStatus := mysqlHelper.GetColInt(dt, "call_status")
				regionCode := mysqlHelper.GetColString(dt, "region_code")
				//发送通知
				for i := 0; i < 3; i++ {
					regionCodes := make([]string, 0)
					if regionCode != "" {
						regionCodes = strings.Split(regionCode, ",")
					}

					resp := zjservice.SyncSeckillMsg(productId, productSId, callStatus, price, regionCodes)
					if resp == nil {
						log.Warnf("同步秒杀信息请求失败")
						continue
					}
					if resp.Code != 0 {
						log.Warnf("同步秒杀信息失败,code:%d ,msg: %s", resp.Code, resp.Msg)
						continue
					}
					log.Infof("同步秒杀成功，serviceId: %d,sdId: %d,callStatus: %d,regionCode: %v", productId, productSId, callStatus, regionCodes)
					break
				}

				//任务置为无效
				seckillId := mysqlHelper.GetColInt(dt, "seckill_id")
				p.CanclSeckillCallTask(seckillId, callStatus)

			}
		}
	}
}

//遍历秒杀缓存，添加或更新秒杀任务
func (p *ZJSeckillInfoService) loopSeckillMemory() {
	defer func() {
		if err := recover(); err != nil {
			log.Errorf("遍历秒杀缓存失败,err: %v", err)
		}
		//重启定时任务
		go p.loopSeckillMemory()
	}()

	for {
		select {
		case <-time.After(time.Minute):
			for k, v := range p.zjSeckillInfo {
				nowTick := time.Now().Unix()
				if v.Status == 1 {
					//查当前id秒杀任务是否存在
					sql := `select count(0) num from seckill_call_task where seckill_id=? and status=1`
					mysqlHelper := db.GetHomePageInfoMysqlHelper()
					result, err := mysqlHelper.Query(sql, k)
					if err != nil {
						log.Errorf("查询秒杀任务失败。loopSeckillMemory！ err:%s", err.Error())
						continue
					}
					if len(result) > 0 {
						num := mysqlHelper.GetColInt(result[0], "num")
						if num > 0 {
							//存在
							if v.StartTick > nowTick {
								GetZJSeckillUserService().UpdateSeckillCallTask(k, 1, v.StartTick)
								log.Infof("定时改变同步任务~ id:%d ,status:1 ,task:%d", k, v.StartTick)
							}
							if v.SeckillStart > nowTick+600 { //秒杀开始前十分钟
								GetZJSeckillUserService().UpdateSeckillCallTask(k, 2, v.SeckillStart)
								log.Infof("定时改变同步任务~ id:%d ,status:2 ,task:%d", k, v.SeckillStart)
							}
							if v.SeckillEnd > nowTick+600 {
								GetZJSeckillUserService().UpdateSeckillCallTask(k, 3, v.SeckillEnd)
								log.Infof("定时改变同步任务~ id:%d ,status:3 ,task:%d", k, v.SeckillEnd)

							}
						} else {
							//不存在，添加任务
							if v.StartTick > nowTick {
								regionCode := v.RegionCode
								if strings.Contains(regionCode, "all") {
									regionCode = ""
								}
								GetZJSeckillUserService().AddSeckillCallTask(k, v.SeckillProductId, v.SeckillProductSid, 1, v.Price, v.StartTick, regionCode)
								GetZJSeckillUserService().AddSeckillCallTask(k, v.SeckillProductId, v.SeckillProductSid, 2, v.Price, v.SeckillStart, regionCode)
								GetZJSeckillUserService().AddSeckillCallTask(k, v.SeckillProductId, v.SeckillProductSid, 3, v.Price, v.SeckillEnd, regionCode)
								log.Infof("添加任务~1,2,3!!!id:%d", k)
							}

						}
					}
				}
			}
		}
	}
}
